package com.huawang.mdesign.model.service.inter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huawang.business.command.CommandAddType;
import com.huawang.business.command.CommandParameter;
import com.huawang.business.command.definition.ICommand;
import com.huawang.business.command.executer.CommandExecutor;
import com.huawang.business.command.factory.CommandFactory;
import com.huawang.business.constants.*;
import com.huawang.business.data.fix.entity.ModelFixResult;
import com.huawang.business.data.share.core.IQueryShareService;
import com.huawang.business.data.share.entity.UseProject;
import com.huawang.business.data.state.ISaveStateService;
import com.huawang.business.dto.AddModelDTO;
import com.huawang.business.dto.MergeVariationDTO;
import com.huawang.business.dto.MetaClassInstanceTreeNode;
import com.huawang.business.dto.ProjectDTO;
import com.huawang.business.dto.project.ModelDependency;
import com.huawang.business.dto.project.Project;
import com.huawang.business.dto.project.ProjectConfig;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.business.service.cowork.ICoworkService;
import com.huawang.business.service.init.InitializeService;
import com.huawang.business.service.judge.OutSideTip;
import com.huawang.business.service.judge.TipService;
import com.huawang.business.service.model.ImportHandler;
import com.huawang.business.service.model.base.ModelManagerConfig;
import com.huawang.business.service.model.core.project.UsageProjectManager;
import com.huawang.business.service.transaction.TransactionServiceImpl;
import com.huawang.business.service.model.base.UMLFacility;
import com.huawang.business.service.model.base.UmlService;
import com.huawang.business.service.model.core.InternalRequirementService;
import com.huawang.business.service.model.core.InternalUmlService;
import com.huawang.business.service.model.core.display.KeywordsCache;
import com.huawang.business.service.model.core.project.InternalProjectService;
import com.huawang.business.service.model.core.project.ProjectManager;
import com.huawang.business.util.InstanceVoUtils;
import com.huawang.business.util.ValidateDataUtil;
import com.huawang.business.vo.CopyInfoVo;
import com.huawang.business.vo.CopyResultVo;
import com.huawang.business.vo.ModelResultVo;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.cmof.reflection.impl.BasicRElement;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.core.definition.mof.util.SnowflakeIdWorkerUtil;
import com.huawang.core.definition.sysml.data.DefinitionStoreRepository;
import com.huawang.core.semantics.constants.ModelCreatorType;
import com.huawang.core.semantics.entity.ExportOutsideElementInfo;
import com.huawang.core.semantics.entity.ExportOutsideElementResult;
import com.huawang.core.semantics.entity.persistence.ImportPackageResult;
import com.huawang.core.semantics.entity.persistence.ProfileChange;
import com.huawang.core.semantics.entity.persistence.ProfileConfig;
import com.huawang.core.semantics.entity.persistence.ProfileMessage;
import com.huawang.core.semantics.entity.persistence.variation.MofModelVariation;
import com.huawang.core.semantics.entity.queryResult.UpdatePropertyNames;
import com.huawang.core.semantics.entity.transaction.ExecutingRecordResult;
import com.huawang.core.semantics.entity.transaction.LocalTransaction;
import com.huawang.core.semantics.exception.*;
import com.huawang.core.semantics.persistence.IPersistenceBaseService;
import com.huawang.core.semantics.utils.TransactionUtil;
import com.huawang.mdesign.model.service.dto.*;
import com.huawang.mdesign.model.service.util.ReadMd3Utils;
import com.huawang.mdesign.model.service.vo.*;
import com.huawang.xmlImport.service.ExportService;
import com.huawang.xmlImport.vo.ExportXmiDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.huawang.business.constants.ModelActionName.*;
import static com.huawang.business.constants.ProfileConstants.*;
import static com.huawang.business.service.model.core.project.ProjectManager.DATABASE;
import static com.huawang.business.service.model.core.project.ProjectManager.MD3;

@Service
@Slf4j
public class ProjectService {
    public Project createTemplate(ProjectTemplateCreateDto dto) {
        ValidateDataUtil.isNotNull(dto.getDefaultSaveDir(), ErrorCode.DEFAULT_DIR_NULL);
        final String projectId = dto.getProjectId();
        Project project = projectManager.getProject(projectId);
        if (project != null) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_REPEAT);
        }

        ReadMd3Utils.MD3FileInfo md3pInfo = ReadMd3Utils.unZip(dto.getTemplatePath());
        try {
            String currentId = SnowflakeIdWorkerUtil.getId();
            final ProjectVo template = new ObjectMapper().readValue(md3pInfo.readMofProject(), ProjectVo.class);
            final ProjectConfig config = md3pInfo.readConfig();
            final List<ModelDependency> dependencies =
                    config.getDependencies().stream().map(it -> new ModelDependency(it.get("profileName"),
                                    Long.valueOf(it.get("profileVersion"))))
                            .collect(Collectors.toList());
            project = projectManager.createAndActive(projectId, dependencies, currentId,
                    dto.getDefaultSaveDir());
            if (StringUtils.isNotEmpty(dto.getProjectType())) {
                project.setProjectType(dto.getProjectType());
            }

            final List<ModelDependency> initProfile = DEFAULT_PROFILE.stream().map(it ->
                    new ModelDependency(it, 1L)).collect(Collectors.toList());
            Set<String> profileIds = new HashSet<>(DEFAULT_PROFILE);
            this.internalProjectService.setGlobalWriteableState(projectId, true);
            profileIds.addAll(initProfileDependency(dependencies, dto.getProfileLibPath(), initProfile,
                    dto.getProfileLibPath(), project));
            project.setDependencies(dependencies);
            this.initializeService.initialize(projectId, false, true, true);
            final MetaClassInstance rootModel = createRootModel(project);
            projectManager.flushDb(projectId);
            project.setRootModel(rootModel.getId());
            this.iSaveStateService.setIsCoWork(projectId, true);
            String dbPath = projectManager.extractProfileDb(dto.getTemplatePath(), project, rootModel.getId()
                    , project.getDefaultSaveDir());
            if (dbPath == null) {
                throw AbortExecutionException.build(ErrorCode.EXTRACT_DB_FILE_ERROR);
            }

            log.info("newRootId:{}, oldRootId:{}", project.getRootModel(), template.getRootModel());
            log.info("dependency:{}", dependencies);
            ImportPackageResult result = persistenceBaseService.importPackageFromDbToFacility(projectId,
                    dbPath, rootModel.getId(), template.getRootModel());
            if (StringUtils.isNotBlank(result.getPackageName())) {
                umlService.updateModel(projectId, rootModel.getId(), UMLDefinitionConstants.NamedElement_name,
                        result.getPackageName());
            }
            this.initializeService.initialize(projectId, false, true, true);
            internalProjectService.setProfileOwner(project, rootModel, new HashSet<>(profileIds));
            this.iSaveStateService.setIsLoggingVariation(projectId, true);
            List<CopyInfoVo> templateIdMap = result.getInstanceIdMap().entrySet().stream().map(it -> {
                CopyInfoVo copyInfoVo = new CopyInfoVo();
                copyInfoVo.setOldId(it.getKey());
                copyInfoVo.setNewId(it.getValue());
                return copyInfoVo;
            }).collect(Collectors.toList());
            CopyInfoVo rootVo = new CopyInfoVo();
            rootVo.setOldId(template.getRootModel());
            rootVo.setNewId(project.getRootModel());
            templateIdMap.add(rootVo);
            project.setTemplateIdMap(templateIdMap);
        } catch (CommandException | JsonProcessingException e) {
            log.error("模板项目创建失败");
            throw AbortExecutionException.build(ErrorCode.TEMPLATE_PROJECT_ERROR, e);
        } catch (Exception e) {
            log.error("", e);
        } finally {
            this.internalProjectService.setGlobalWriteableState(projectId, false);
        }

        return project;
    }
}


